#include <assert.h>

#include "webrtcVadInst.h"

#include"../utils/log/recoProxyLog.h"

void* webrtcVadInst::init()
{
	_pVadRingBuffer = make_shared<vadRingBuffer>(50);
	_pInst = WebRtcVad_Create();
	WebRtcVad_Init(_pInst);
	_pThread = make_shared< thread>(&webrtcVadInst::run,this);
	return _pInst;
}
void webrtcVadInst::reset()
{
}

void webrtcVadInst::run()
{
//#define DEBUGALL
#ifdef DEBUGALL
	FILE* fp = fopen("./testout.pcm","w");
#endif
	while(1)
	{
		sData data	= getBuffer()->readItem();
		if(data->getDataLen() > 0)
		{
			//printf("Feed Data %p, Len:%d\n", data->getData(),data->getDataLen());
			char forPrint[1024];
			sprintf(forPrint,"Get Data %p, Len=%d",data->getData(), data->getDataLen());
#ifdef LOGFILE
			log::getInstance()->getLog()->info(forPrint);
#else
			printf("%s\n",forPrint);
#endif
			feedData(data);
#ifdef DEBUGALL
			fwrite(data->getData(),data->getDataLen(),sizeof(char),fp);
#endif
		}
		else
		{
			assert(getCloseCbFunc());
			assert(getCbObj());
			vadCloseCb f = getCloseCbFunc();
			f(getCbObj());
			//_pAsrInst->close();
#ifdef DEBUGALL
		fclose(fp);
#endif
			break;
		}
	}
}

void webrtcVadInst::writeBuffer(char* pData, int iLen)
{
	sData ssData = make_shared<data>(pData,iLen);
	char forPrint[1024];
	sprintf(forPrint,"Feed data %p, Len is %d",pData,iLen);
#ifdef LOGFILE
	log::getInstance()->getLog()->info(forPrint);
#else
	printf("%s\n",forPrint);
#endif
	getBuffer()->addItem(ssData);
}

void webrtcVadInst::feedData(sData pData)
{
	++_iTotalPackage;
	++_iStartIndex;
	++_iEndIndex;
	_iStartIndex %= WEBRTCVAD_MAX_START_POINTS;
	_iEndIndex %= WEBRTCVAD_MAX_END_POINTS;
	//unsigned char to short
	int iLen = pData->getDataLen();
	vadVars* var = & _var;
	var->_iPos += iLen;
	var->_iTime += iLen * 1000/(2*getOptions()->_iSampleRatio);
	assert(iLen %2 ==0);
	int iTempLen = iLen/2;
	int16_t* pTempData = new int16_t[iTempLen];
	memcpy(pTempData,pData->getData(),iLen);
	int isSpeech = WebRtcVad_Process(_pInst,8000,pTempData,iTempLen);
	delete []pTempData;
	printf("Rate:%d, Time:%d,IsSpeech:%d\n",getOptions()->_iSampleRatio, var->_iTime, isSpeech);
	_startFlags[_iStartIndex] = (isSpeech ==1) ? 1:0;
	_endFlags[_iEndIndex] = (isSpeech ==1) ? 1:0;
	if(!var->_iIsBegin )
	{
		_pVadRingBuffer->addItem(pData);
		if(1 ==isSpeech)
		{
			int iStartCount = 0;
			for(auto i = 0; i < WEBRTCVAD_MAX_START_POINTS; ++i)
				if (1 == _startFlags[i])
					++iStartCount;	
			if(iStartCount > 0.8 * WEBRTCVAD_MAX_START_POINTS )
			{
				var->_iIsBegin = 1;
				var->_iFirstFrame =1;
				printf("Detect speech at active %d ms\n",var->_iTime );
				//assert(WEBRTCVAD_MAX_START_POINTS == _pVadRingBuffer->size());
				int iBeginPos = var->_iPos -  WEBRTCVAD_MAX_START_POINTS;
				assert(iBeginPos >= 0);
				int iBeginTime = iBeginPos * 1000/(2*getOptions()->_iSampleRatio);
				int sz =  _pVadRingBuffer->getDeque().size() - WEBRTCVAD_MAX_START_POINTS;
				sz = (sz > 0)?sz:0;
				for( auto it =  _pVadRingBuffer->getDeque().begin() + sz; it != _pVadRingBuffer->getDeque().end();++it)
				{
					vadCallBackFunc f = getCbFunc();
					f(getCbObj(),static_cast<unsigned char*>((*it)->getData()),(*it)->getDataLen(),var);		
				}
				getCbUpdateTimeFunc()(getCbObj(),VAD_TIME_START,iBeginTime);

			}
		}
	}
	else if(!var->_iIsEnd)
	{
		   	int iEndCount = 0;
            for(auto i = 0; i < WEBRTCVAD_MAX_END_POINTS; ++i)
                if (1 == _endFlags[i])
                    ++iEndCount;
            if(iEndCount < 0.8 * WEBRTCVAD_MAX_START_POINTS)
            {
				var->_iIsBegin = 0;
                var->_iIsEnd= 1;
				++var->_iIndex;
				getCbUpdateTimeFunc()(getCbObj(),VAD_TIME_END,var->_iTime);
                printf("Detect speech inactive at %d ms\n",var->_iTime );
            }
			vadCallBackFunc f = getCbFunc();
			f(getCbObj(),static_cast<unsigned char*>(pData->getData()),iLen,var);		

	}
	if (var->_iIsEnd)
	{
		var->_iIsBegin = 0;
		var->_iIsEnd= 0;
	}
}
